package org.ricks.lambda.methodhandle;

import java.lang.invoke.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class DynamicInvoker {
    private static final Map<Method, MethodHandle> methodHandleCache = new HashMap<>();
    private static final Map<Method, Object> lambdaCache = new HashMap<>();

    // 获取函数式接口实例
    public static <T> T getLambda(Object target, Method method, Class<T> functionalInterface)
            throws Throwable {
        if (lambdaCache.containsKey(method)) {
            return functionalInterface.cast(lambdaCache.get(method));
        }

        MethodHandle handle = getMethodHandle(target, method);
        CallSite site = LambdaMetafactory.metafactory(
                MethodHandles.lookup(),
                "apply",  // 函数式接口方法名
                MethodType.methodType(functionalInterface, target.getClass()),
                MethodType.methodType(Object.class, Object.class), // SAM签名
                handle,
                handle.type()
        );

        T lambda = (T) site.getTarget().invoke(target);
        lambdaCache.put(method, lambda);
        return lambda;
    }

    // 获取MethodHandle并缓存
    private static MethodHandle getMethodHandle(Object target, Method method)
            throws NoSuchMethodException, IllegalAccessException {
        if (methodHandleCache.containsKey(method)) {
            return methodHandleCache.get(method);
        }

        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle handle = lookup.unreflect(method);
        methodHandleCache.put(method, handle);
        return handle;
    }
}
